/*
 * ShapeReader.cpp
 *
 *  Created on: 2009/02/17
 *      Author: Yongshik Cho
 */

#include "ShapeReader.h"
#include "TileReader.h"
#include "CollisionReader.h"
#include "TweenReader.h"
#include "PathReader.h"
#include "../ScriptManager.h"
#include "../core/Rect2D.h"


const std::string ShapeReader::_LINESTYLE_TAG		= "LineStyle";
const std::string ShapeReader::_FILLSTYLE_TAG		= "FillStyle";
const std::string ShapeReader::_LINECOLOR_TAG		= "LineColor";
const std::string ShapeReader::_FILLCOLOR_TAG		= "FillColor";
const std::string ShapeReader::_LINEWIDTH_TAG		= "LineWidth";

const std::string ShapeReader::_LINE_NONE_TAG		= "none";
const std::string ShapeReader::_LINE_SOLID_TAG		= "solid";
const std::string ShapeReader::_FILL_NONE_TAG		= "none";
const std::string ShapeReader::_FILL_SOLID_TAG		= "solid";


ShapeObject* ShapeReader::parse(TiXmlElement* element, RenderObjectContainer* roc)
{
	uint32 color32, blendColor;
	double lineWidth = 0.0;
	Color color;
	char *sCenterType, *sCollideType, *sLocked, *sVisible, *sBlendColor, *sVisibleRect, *sVisibleCenter;

	char* sName = (char*)element->Attribute(TileReader::_NAME_TAG.c_str());
	char* sType = (char*)element->Attribute(PathReader::_TYPE_TAG.c_str());
	char* sClosed = (char*)element->Attribute(PathReader::_CLOSED_TAG.c_str());

	TiXmlElement* node = element->FirstChildElement(TileReader::_NAME_TAG.c_str()); if(node) sName = (char*)node->GetText();
	node = element->FirstChildElement(PathReader::_TYPE_TAG.c_str()); if(node) sType = (char*)node->GetText();
	node = element->FirstChildElement(PathReader::_CLOSED_TAG.c_str()); if(node) sClosed = (char*)node->GetText();

	ShapeObject* shape = new ShapeObject();
	if(!shape)
		AltoThrow(Exception::ERR_MEMORY);

	if(sName)
#ifdef UNICODE
	{
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, sName, (int32)strlen(sName), wstr, 512);
		shape->setName(wstr);
	}
#else
		shape->setName(sName);
#endif

	if(sType)
	{
		if(PathReader::_LINEAR_TAG == sType)
		{
			shape->setType(Curve2D::_LINEAR);
		}
		else if(PathReader::_BEZIER_TAG == sType)
		{
			shape->setType(Curve2D::_BEZIER);
		}
	}

	if(sClosed)
	{
		if(PathReader::_TRUE_TAG == sClosed)
			shape->setClosed(true);
		else if(PathReader::_FALSE_TAG == sClosed)
			shape->setClosed(false);
	}

	sCenterType = (char*)element->Attribute(TileReader::_CENTERTYPE_TAG.c_str());
	sCollideType = (char*)element->Attribute(TileReader::_COLLIDETYPE_TAG.c_str());
	sBlendColor = (char*)element->Attribute(TileReader::_BLENDCOLOR_TAG.c_str());
	sLocked = (char*)element->Attribute(TileReader::_LOCKED_TAG.c_str());
	sVisibleRect = (char*)element->Attribute(TileReader::_VISIBLE_RECT_TAG.c_str());
	sVisibleCenter = (char*)element->Attribute(TileReader::_VISIBLE_CENTER_TAG.c_str());
	sVisible = (char*)element->Attribute(TileReader::_VISIBLE_TAG.c_str());
	char* sBlendType = (char*)element->Attribute(TileReader::_BLENDTYPE_TAG.c_str());
	char* sSort = (char*)element->Attribute(TileReader::_SORT_TAG.c_str());
	char* sLineStyle = (char*)element->Attribute(_LINESTYLE_TAG.c_str());
	char* sFillStyle = (char*)element->Attribute(_FILLSTYLE_TAG.c_str());
	char* sLineColor = (char*)element->Attribute(_LINECOLOR_TAG.c_str());
	char* sFillColor = (char*)element->Attribute(_FILLCOLOR_TAG.c_str());
	element->Attribute(_LINEWIDTH_TAG.c_str(), &lineWidth);

	node = element->FirstChildElement(TileReader::_CENTERTYPE_TAG.c_str()); if(node) sCenterType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_COLLIDETYPE_TAG.c_str()); if(node) sCollideType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_BLENDCOLOR_TAG.c_str()); if(node) sBlendColor = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_LOCKED_TAG.c_str()); if(node) sLocked = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_VISIBLE_RECT_TAG.c_str()); if(node) sVisibleRect = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_VISIBLE_CENTER_TAG.c_str()); if(node) sVisibleCenter = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_VISIBLE_TAG.c_str()); if(node) sVisible = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_BLENDTYPE_TAG.c_str()); if(node) sBlendType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_SORT_TAG.c_str()); if(node) sSort = (char*)node->GetText();
	node = element->FirstChildElement(_LINESTYLE_TAG.c_str()); if(node) sLineStyle = (char*)node->GetText();
	node = element->FirstChildElement(_FILLSTYLE_TAG.c_str()); if(node) sFillStyle = (char*)node->GetText();
	node = element->FirstChildElement(_LINECOLOR_TAG.c_str()); if(node) sLineColor = (char*)node->GetText();
	node = element->FirstChildElement(_FILLCOLOR_TAG.c_str()); if(node) sFillColor = (char*)node->GetText();
	node = element->FirstChildElement(_LINEWIDTH_TAG.c_str()); if(node) lineWidth = atof(node->GetText());

	if(sCenterType)
	{
		if(sCenterType == TileReader::_CENTER_LT_TAG)
			shape->setCenterType(Rect2D::CENTER_LT);
		else if(sCenterType == TileReader::_CENTER_CT_TAG)
			shape->setCenterType(Rect2D::CENTER_CT);
		else if(sCenterType == TileReader::_CENTER_RT_TAG)
			shape->setCenterType(Rect2D::CENTER_RT);
		else if(sCenterType == TileReader::_CENTER_LM_TAG)
			shape->setCenterType(Rect2D::CENTER_LM);
		else if(sCenterType == TileReader::_CENTER_CM_TAG)
			shape->setCenterType(Rect2D::CENTER_CM);
		else if(sCenterType == TileReader::_CENTER_RM_TAG)
			shape->setCenterType(Rect2D::CENTER_RM);
		else if(sCenterType == TileReader::_CENTER_LB_TAG)
			shape->setCenterType(Rect2D::CENTER_LB);
		else if(sCenterType == TileReader::_CENTER_CB_TAG)
			shape->setCenterType(Rect2D::CENTER_CB);
		else if(sCenterType == TileReader::_CENTER_RB_TAG)
			shape->setCenterType(Rect2D::CENTER_RB);
	}

	if(sCollideType)
	{
		if(sCollideType == TileReader::_COLLIDABLE_PIXEL_TAG)
			shape->setCollideType(Collidable::COLLIDABLE_PIXEL);
		else if(sCollideType == TileReader::_COLLIDABLE_LINE_TAG)
			shape->setCollideType(Collidable::COLLIDABLE_LINE);
		else if(sCollideType == TileReader::_COLLIDABLE_TRIANGLE_TAG)
			shape->setCollideType(Collidable::COLLIDABLE_TRIANGLE);
		else if(sCollideType == TileReader::_COLLIDABLE_RECT_TAG)
			shape->setCollideType(Collidable::COLLIDABLE_RECT);
		else if(sCollideType == TileReader::_COLLIDABLE_POLYGON_TAG)
			shape->setCollideType(Collidable::COLLIDABLE_POLYGON);
	}

	if(sBlendColor)
	{
		sscanf(sBlendColor, "%x", &blendColor);
		color = Color::fromARGB((float)((blendColor>>24)&0xFF)/255.f, (float)((blendColor>>16)&0xFF)/255.f,
				(float)((blendColor>>8)&0xFF)/255.f, (float)((blendColor>>0)&0xFF)/255.f);
		shape->setBlendColor(color);
	}

	shape->setLineWidth((float)lineWidth);

	if(sFillStyle)
	{
		if(sFillStyle == _FILL_NONE_TAG)
			shape->setFillStyle(ShapeObject::FILL_NONE);
		else if(sFillStyle == _FILL_SOLID_TAG)
			shape->setFillStyle(ShapeObject::FILL_SOLID);
	}

	if(sLineStyle)
	{
		if(sLineStyle == _LINE_NONE_TAG)
			shape->setLineStyle(ShapeObject::LINE_NONE);
		else if(sLineStyle == _LINE_SOLID_TAG)
			shape->setLineStyle(ShapeObject::LINE_SOLID);
	}

	if(sFillColor)
	{
		sscanf(sFillColor, "%x", &color32);
		color = Color::fromARGB((float)((color32>>24)&0xFF)/255.f, (float)((color32>>16)&0xFF)/255.f,
				(float)((color32>>8)&0xFF)/255.f, (float)((color32>>0)&0xFF)/255.f);
		shape->setFillColor(color);
	}

	if(sLineColor)
	{
		sscanf(sLineColor, "%x", &color32);
		color = Color::fromARGB((float)((color32>>24)&0xFF)/255.f, (float)((color32>>16)&0xFF)/255.f,
				(float)((color32>>8)&0xFF)/255.f, (float)((color32>>0)&0xFF)/255.f);
		shape->setLineColor(color);
	}

	if(sLocked)
	{
		if(sLocked == TileReader::_TRUE_TAG)
			shape->setLocked(true);
		else if(sLocked == TileReader::_FALSE_TAG)
			shape->setLocked(false);
	}

	if(sVisibleRect)
	{
		if(sVisibleRect == TileReader::_TRUE_TAG)
			shape->setVisibleRect(true);
		else if(sVisibleRect == TileReader::_FALSE_TAG)
			shape->setVisibleRect(false);
	}

	if(sVisibleCenter)
	{
		if(sVisibleCenter == TileReader::_TRUE_TAG)
			shape->setVisibleCenter(true);
		else if(sVisibleCenter == TileReader::_FALSE_TAG)
			shape->setVisibleCenter(false);
	}

	if(sVisible)
	{
		if(sVisible == TileReader::_TRUE_TAG)
			shape->setVisible(true);
		else if(sVisible == TileReader::_FALSE_TAG)
			shape->setVisible(false);
	}

	if(sSort)
	{
		if(sSort == TileReader::_TRUE_TAG)
			shape->setSort(true);
		else if(sSort == TileReader::_FALSE_TAG)
			shape->setSort(false);
	}

	if(sBlendType)
	{
		if(sBlendType == TileReader::_BLEND_NONE_TAG)
			shape->setBlendType(Color::BLEND_NONE);
		else if(sBlendType == TileReader::_BLEND_ALPHA_TAG)
			shape->setBlendType(Color::BLEND_ALPHA);
		else if(sBlendType == TileReader::_BLEND_ADD_TAG)
			shape->setBlendType(Color::BLEND_ADD);
		else if(sBlendType == TileReader::_BLEND_SUB_TAG)
			shape->setBlendType(Color::BLEND_SUB);
		else if(sBlendType == TileReader::_BLEND_DARKEN_TAG)
			shape->setBlendType(Color::BLEND_DARKEN);
		else if(sBlendType == TileReader::_BLEND_LIGHTEN_TAG)
			shape->setBlendType(Color::BLEND_LIGHTEN);
		else if(sBlendType == TileReader::_BLEND_MULTIPLY_TAG)
			shape->setBlendType(Color::BLEND_MULTIPLY);
		else if(sBlendType == TileReader::_BLEND_SCREEN_TAG)
			shape->setBlendType(Color::BLEND_SCREEN);
		else if(sBlendType == TileReader::_BLEND_DIFFERENCE_TAG)
			shape->setBlendType(Color::BLEND_DIFFERENCE);
		else if(sBlendType == TileReader::_BLEND_INVERSE_DIFFERENCE_TAG)
			shape->setBlendType(Color::BLEND_INVERSE_DIFFERENCE);
		else if(sBlendType == TileReader::_BLEND_INVERT_TAG)
			shape->setBlendType(Color::BLEND_INVERT);
		else if(sBlendType == TileReader::_BLEND_DODGE_TAG)
			shape->setBlendType(Color::BLEND_DODGE);
	}

	{
		for(TiXmlElement* attach=element->FirstChildElement(TileReader::_ATTACHMENT_TAG.c_str());
		attach;attach=attach->NextSiblingElement(TileReader::_ATTACHMENT_TAG.c_str()))
		{
			parseAttachment(attach, (Renderable*)shape);
		}

		for(TiXmlElement* collision=element->FirstChildElement(TileReader::_COLLISION_TAG.c_str());
			collision;collision=collision->NextSiblingElement(TileReader::_COLLISION_TAG.c_str()))
		{
			Collidable* collidable = CollisionReader::parse(collision);
			if(collidable)
				shape->addCollidable(collidable);
		}

		int32 x=0, y=0;
		double sx=1.f, sy=1.f, angle=0.f;

		TiXmlElement* origin = element->FirstChildElement(TileReader::_ORIGIN_TAG.c_str());
		if(origin)
		{
			origin->Attribute(TileReader::_X_TAG.c_str(), &x);
			node = origin->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
			origin->Attribute(TileReader::_Y_TAG.c_str(), &y);
			node = origin->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

			shape->setOrigin(Vector2D((float)x, (float)y));
		}

		TiXmlElement* up = element->FirstChildElement(TileReader::_UP_TAG.c_str());
		if(up)
		{
			up->Attribute(TileReader::_X_TAG.c_str(), &x);
			node = up->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
			up->Attribute(TileReader::_Y_TAG.c_str(), &y);
			node = up->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

			shape->setUp(Vector2D((float)x, (float)y));
		}

		TiXmlElement* position = element->FirstChildElement(TileReader::_POSITION_TAG.c_str());
		if(position)
		{
			position->Attribute(TileReader::_X_TAG.c_str(), &x);
			node = position->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
			position->Attribute(TileReader::_Y_TAG.c_str(), &y);
			node = position->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

			shape->setPosition(Vector2D((float)x, (float)y));
		}

		TiXmlElement* rotation = element->FirstChildElement(TileReader::_ROTATION_TAG.c_str());
		if(rotation)
		{
			rotation->Attribute(TileReader::_ANGLE_TAG.c_str(), &angle);
			node = rotation->FirstChildElement(TileReader::_ANGLE_TAG.c_str()); if(node) angle = atof(node->GetText());

			shape->setRotation((float)angle);
		}

		TiXmlElement* scale = element->FirstChildElement(TileReader::_SCALE_TAG.c_str());
		if(scale)
		{
			scale->Attribute(TileReader::_X_TAG.c_str(), &sx);
			node = scale->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) sx = atof(node->GetText());
			scale->Attribute(TileReader::_Y_TAG.c_str(), &sy);
			node = scale->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) sy = atof(node->GetText());

			shape->setScale(Vector2D((float)sx, (float)sy));
		}
	}

	//read information about tween
	for(TiXmlElement* twn=element->FirstChildElement(TileReader::_TWEEN_TAG.c_str());twn;twn=twn->NextSiblingElement(TileReader::_TWEEN_TAG.c_str()))
	{
		TweenReader::parse(twn, shape);
	}

	int32 x=0, y=0, weight;
	double angle=0.f;

	for(TiXmlElement* elem=element->FirstChildElement(PathReader::_NODE_TAG.c_str());elem;elem=elem->NextSiblingElement(PathReader::_NODE_TAG.c_str()))
	{
		elem->Attribute(PathReader::_WEIGHT_TAG.c_str(), &weight);
		node = elem->FirstChildElement(PathReader::_WEIGHT_TAG.c_str()); if(node) weight = atoi(node->GetText());

		TiXmlElement* position = elem->FirstChildElement(PathReader::_POSITION_TAG.c_str());
		if(position)
		{
			position->Attribute(PathReader::_X_TAG.c_str(), &x);
			node = position->FirstChildElement(PathReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
			position->Attribute(PathReader::_Y_TAG.c_str(), &y);
			node = position->FirstChildElement(PathReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());
		}

		TiXmlElement* rotation = elem->FirstChildElement(PathReader::_ROTATION_TAG.c_str());
		if(rotation)
		{
			rotation->Attribute(PathReader::_ANGLE_TAG.c_str(), &angle);
			node = rotation->FirstChildElement(PathReader::_ANGLE_TAG.c_str()); if(node) angle = atof(node->GetText());
		}

		shape->addNode(BezierNode(Vector2D((float)x, (float)y), (float)angle, (float)weight));
	}

	parseScripts(element, shape);

	return shape;
}

void ShapeReader::parseScripts(TiXmlElement* element, ShapeObject* shape)
{
	char* scriptFile = (char*)element->Attribute(TileReader::_SCRIPT_FILE_TAG.c_str());
	TiXmlElement* node = element->FirstChildElement(TileReader::_SCRIPT_FILE_TAG.c_str()); if(node) scriptFile = (char*)node->GetText();

	if(scriptFile)
	{
#ifdef UNICODE
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, scriptFile, (int32)strlen(scriptFile), wstr, 512);
		ScriptManager::GetInstance().load(wstr);
#else
		ScriptManager::GetInstance().load(scriptFile);
#endif
	}

	char* onLoad = (char*)element->Attribute(TileReader::_ON_LOAD_TAG.c_str());
	node = element->FirstChildElement(TileReader::_ON_LOAD_TAG.c_str()); if(node) onLoad = (char*)node->GetText();

	if(onLoad)
	{
		//call script function
#ifdef UNICODE
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, onLoad, (int32)strlen(onLoad), wstr, 512);
		SquirrelFunction<void>((const SQChar*)wstr)(shape);
#else
		SquirrelFunction<void>((const SQChar*)onLoad)(shape);
#endif
	}
}

void ShapeReader::parseAttachment(TiXmlElement* element, Renderable* renderable)
{
	char* sName = (char*)element->Attribute(TileReader::_NAME_TAG.c_str());
	TiXmlElement* node = element->FirstChildElement(TileReader::_NAME_TAG.c_str()); if(node) sName = (char*)node->GetText();

	TiXmlElement* position = element->FirstChildElement(TileReader::_POSITION_TAG.c_str());
	if(position)
	{
		int32 x = 0, y = 0;

		position->Attribute(TileReader::_X_TAG.c_str(), &x);
		node = position->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
		position->Attribute(TileReader::_Y_TAG.c_str(), &y);
		node = position->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

		if(sName)
#ifdef UNICODE
		{
			TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
			::MultiByteToWideChar(CP_UTF8, 0, sName, (int32)strlen(sName), wstr, 512);
			renderable->addAttachment(wstr, Vector2D((float)x, (float)y));
		}
#else
			renderable->addAttachment(sName, Vector2D((float)x, (float)y));
#endif
		else
			renderable->addAttachment(_T(""), Vector2D((float)x, (float)y));
	}
}
